home *** CD-ROM | disk | FTP | other *** search
- //-----------------------------------------------------------------------------
- // File: populate.cpp
- //
- // Desc: This file contains the population functions. These are all
- // accessed through PopulateAppropriately(). That function creates
- // views & controls based on the type of the device that the passed
- // DeviceUI represents.
- //
- // Copyright (C) Microsoft Corporation. All Rights Reserved.
- //-----------------------------------------------------------------------------
-
- #include "common.hpp"
-
-
- // these functions are internal to this filed, called only by
- // PopulateAppropriately().
- HRESULT PopulateViaGetImageInfo(CDeviceUI &ui);
- HRESULT PopulateFromImageInfoHeader(CDeviceUI &ui, const DIDEVICEIMAGEINFOHEADERW &);
- HRESULT PopulateListView(CDeviceUI &ui);
- HRESULT PopulateErrorView(CDeviceUI &ui);
-
-
- // Clears the entire passed DeviceUI, then fills it with views and
- // controls based on device type. Tries to gaurantee that there will
- // be at least one view.
- HRESULT PopulateAppropriately(CDeviceUI &ui)
- {
- HRESULT hr = S_OK;
-
- // first empty the ui
- ui.Unpopulate();
-
- // get device type
- DWORD dwdt = ui.m_didi.dwDevType;
- DWORD dwType = (DWORD)(LOBYTE(LOWORD(dwdt)));
- DWORD dwSubType = (DWORD)(HIBYTE(LOWORD(dwdt)));
-
- // based on type...
- switch (dwType)
- {
- default:
- // unless its a type we don't ever want views for,
- // populate via the GetImageInfo() API
- hr = PopulateViaGetImageInfo(ui);
- if (SUCCEEDED(hr) && ui.GetNumViews() > 0)
- return hr;
-
- // if it failed or resulted in nothing,
- // clear anything that might've been added
- ui.Unpopulate();
-
- // intentional fallthrough
-
- case DI8DEVTYPE_MOUSE:
- case DI8DEVTYPE_KEYBOARD:
- // for types that we don't ever want views for
- // we populate the list view without trying the above
- hr = PopulateListView(ui);
-
- // if we still failed or don't have any views,
- // populate with error message view
- if (FAILED(hr) || ui.GetNumViews() < 1)
- {
- // empty
- ui.Unpopulate();
-
- // show error message
- hr = PopulateErrorView(ui);
- }
-
- // this function should guarantee success
- assert(!FAILED(hr));
-
- return hr;
- }
- }
-
- // Calls the GetImageInfo() API to get the view images and controls
- // for the entire device, and returns a failure if there's the
- // slightest problem (if GII() fails, or if an image fails to load,
- // etc.)
- HRESULT PopulateViaGetImageInfo(CDeviceUI &ui)
- {
- if (!ui.m_lpDID)
- return E_FAIL;
-
- HRESULT hr = S_OK;
-
- DIDEVICEIMAGEINFOHEADERW m_diImgInfoHdr;
- LPDIDEVICEIMAGEINFOW &lprgdiImgData = m_diImgInfoHdr.lprgImageInfoArray;
-
- ZeroMemory( &m_diImgInfoHdr, sizeof(DIDEVICEIMAGEINFOHEADERW) );
- m_diImgInfoHdr.dwSize = sizeof(DIDEVICEIMAGEINFOHEADERW);
- m_diImgInfoHdr.dwSizeImageInfo = sizeof(DIDEVICEIMAGEINFOW);
-
- // Retrieve the required buffer size.
- hr = ui.m_lpDID->GetImageInfo( &m_diImgInfoHdr );
- if (FAILED(hr))
- {
- etrace1(_T("GetImageInfo() failed while trying to get required buffer size. hr = 0x%08x\n"), hr);
- return E_FAIL;
- }
-
- // Allocate the buffer.
- lprgdiImgData = (LPDIDEVICEIMAGEINFOW) malloc( (size_t)
- (m_diImgInfoHdr.dwBufferSize = m_diImgInfoHdr.dwBufferUsed) );
- if (lprgdiImgData == NULL)
- {
- etrace1(_T("Could not allocate buffer of size %d.\n"), m_diImgInfoHdr.dwBufferSize);
- return E_FAIL;
- }
-
- m_diImgInfoHdr.lprgImageInfoArray = lprgdiImgData;
-
- // Get the display info.
- hr = ui.m_lpDID->GetImageInfo( &m_diImgInfoHdr );
- if (FAILED(hr))
- {
- etrace1(_T("GetImageInfo() failed trying to get image info. hr = 0x%08x\n"), hr);
- free(lprgdiImgData);
- lprgdiImgData = NULL;
- return E_FAIL;
- }
-
- // actually populate now
- hr = PopulateFromImageInfoHeader(ui, m_diImgInfoHdr);
- if (FAILED(hr))
- return hr;
-
- // free stuff
- free(lprgdiImgData);
- lprgdiImgData = NULL;
-
- return S_OK;
- }
-
- // basically does the work for the above function after the header
- // is actually retrieved
- HRESULT PopulateFromImageInfoHeader(CDeviceUI &ui, const DIDEVICEIMAGEINFOHEADERW &dih)
- {
- if (dih.dwSizeImageInfo != sizeof(DIDEVICEIMAGEINFOW))
- {
- etrace(_T("dwSizeImageInfo Incorrect.\n"));
- assert(0);
- return E_FAIL;
- }
- DWORD dwNumElements = dih.dwBufferUsed / dih.dwSizeImageInfo;
- if (dwNumElements * dih.dwSizeImageInfo != dih.dwBufferUsed
- || dih.dwBufferUsed < dih.dwBufferSize)
- {
- etrace(_T("Could not confidently calculate dwNumElements.\n"));
- assert(0);
- return E_FAIL;
- }
-
- DWORD i;
-
- bidirlookup<DWORD, int> offset_view;
-
- {
- for (i = 0; i < dwNumElements; i++)
- if (dih.lprgImageInfoArray[i].dwFlags & DIDIFT_CONFIGURATION)
- {
- LPDIDEVICEIMAGEINFOW lpInfoBase = dih.lprgImageInfoArray;
- DWORD index = i;
- {
- if (lpInfoBase == NULL)
- {
- etrace(_T("lpInfoBase NULL\n"));
- return E_FAIL;
- }
-
- DIDEVICEIMAGEINFOW &info = lpInfoBase[index];
- DWORD dwOffset = index;
-
- // add view info to array
- CDeviceView *pView = ui.NewView();
- if (!pView)
- {
- etrace(_T("Could not create new view.\n"));
- return E_FAIL;
- }
- int nView = pView->GetViewIndex();
-
- // set view's imagepath
- if (!info.tszImagePath)
- {
- etrace(_T("No image path.\n"));
- return E_FAIL;
- }
- LPTSTR tszImagePath = AllocLPTSTR(info.tszImagePath);
- if (!tszImagePath)
- {
- etrace(_T("Could not copy image path.\n"));
- return E_FAIL;
- }
-
- // set the view's image path
- pView->SetImagePath(tszImagePath);
-
- // create bitmap from path
- LPDIRECT3DSURFACE9 lpSurf3D = ui.m_uig.GetSurface3D();
- CBitmap *pbm = CBitmap::CreateViaD3DX(tszImagePath, lpSurf3D);
- free(tszImagePath);
- tszImagePath = NULL;
- if (lpSurf3D)
- {
- lpSurf3D->Release(); // Need to free the surface instance after we are done as AddRef() was called earlier.
- lpSurf3D = NULL;
- }
- if (!pbm)
- {
- etrace(_T("Could not create image from path.\n"));
- return E_FAIL;
- }
-
- // set the view's image
- assert(pbm != NULL);
- pView->SetImage(pbm); // setimage steals the bitmap pointer
- assert(pbm == NULL);
-
- // add conversion from offset to view
- offset_view.add(dwOffset, nView);
- }
- }
- }
-
- {
- for (i = 0; i < dwNumElements; i++)
- {
- DWORD dwFlags = dih.lprgImageInfoArray[i].dwFlags;
-
- if (dwFlags & DIDIFT_OVERLAY)
- {
- LPDIDEVICEIMAGEINFOW lpInfoBase = dih.lprgImageInfoArray;
- DWORD index = i;
- {
- if (lpInfoBase == NULL)
- {
- etrace(_T("lpInfoBase NULL\n"));
- return E_FAIL;
- }
-
- DIDEVICEIMAGEINFOW &info = lpInfoBase[index];
-
- int nViewIndex = 0;
-
- if (!offset_view.getright(info.dwViewID, nViewIndex))
- {
- etrace(_T("Could not get view index\n"));
- return E_FAIL;
- }
-
- if (nViewIndex < 0 || nViewIndex >= ui.GetNumViews())
- {
- etrace1(_T("Invalid view index %d\n"), nViewIndex);
- return E_FAIL;
- }
-
- CDeviceView *pView = ui.GetView(nViewIndex);
- if (!pView)
- {
- etrace1(_T("Couldn't get device view!\n"), nViewIndex);
- return E_FAIL;
- }
-
- CDeviceControl *pControl = pView->NewControl();
- if (!pControl)
- {
- etrace1(_T("Couldn't get device control!\n"), nViewIndex);
- return E_FAIL;
- }
- int nControl = pControl->GetControlIndex();
-
- pControl->SetObjID(info.dwObjID);
- pControl->SetLinePoints(int(info.dwcValidPts), info.rgptCalloutLine);
- pControl->SetCalloutMaxRect(info.rcCalloutRect);
- pControl->SetAlignment(info.dwTextAlign);
- if (info.tszImagePath)
- {
- LPTSTR tszOverlayPath = AllocLPTSTR(info.tszImagePath);
- if (tszOverlayPath)
- {
- pControl->SetOverlayPath(tszOverlayPath);
- free(tszOverlayPath);
- tszOverlayPath = NULL;
- }
- }
- pControl->SetOverlayRect(info.rcOverlay);
- pControl->Init();
- }
- }
- }
- }
-
- return S_OK;
- }
-
- // Enumerates the controls on the device and creates one big list
- // view for the device. Fails if it can't enumerate for some reason.
- HRESULT PopulateListView(CDeviceUI &ui)
- {
- int i;
- HRESULT hr = S_OK;
-
- // we must have the device interface
- if (!ui.m_lpDID)
- return E_FAIL;
-
- // create one view
- CDeviceView *pView = ui.NewView();
- if (!pView)
- return E_FAIL;
-
- // enable scrolling on it
- pView->EnableScrolling();
-
- // get list of controls
- DIDEVOBJSTRUCT os;
- hr = FillDIDeviceObjectStruct(os, ui.m_lpDID);
- if (FAILED(hr))
- return hr;
-
- // if there aren't any, fail
- int n = os.nObjects;
- if (n < 1)
- return E_FAIL;
-
- // run through and create a text for every control to
- // get the sizing
- POINT origin = {0, 0};
- SIZE max = {0, 0};
- for (i = 0; i < n; i++)
- {
- LPTSTR tszName = AllocLPTSTR(os.pdoi[i].tszName);
- CDeviceViewText *pText = pView->AddText(
- (HFONT)ui.m_uig.GetFont(UIE_DEVOBJ),
- ui.m_uig.GetTextColor(UIE_DEVOBJ),
- ui.m_uig.GetBkColor(UIE_DEVOBJ),
- origin,
- tszName);
- free(tszName);
- if (!pText)
- {
- return E_FAIL;
- }
- SIZE tsize = GetRectSize(pText->GetRect());
- if (tsize.cx > max.cx)
- max.cx = tsize.cx;
- if (tsize.cy > max.cy)
- max.cy = tsize.cy;
- }
-
- // Find out if we should use one column or two columns if this is a kbd device.
- BOOL bUseTwoColumns = FALSE;
- if (LOBYTE(LOWORD(ui.m_didi.dwDevType)) == DI8DEVTYPE_KEYBOARD &&
- ((g_sizeImage.cx - DEFAULTVIEWSBWIDTH) >> 1) - max.cx >= MINLISTVIEWCALLOUTWIDTH)
- bUseTwoColumns = TRUE;
-
- // calculate max callout height based on the two possible fonts
- int cmaxh = 0,
- ch = 2 + GetTextHeight((HFONT)ui.m_uig.GetFont(UIE_CALLOUT)),
- chh = 2 + GetTextHeight((HFONT)ui.m_uig.GetFont(UIE_CALLOUTHIGH));
- if (ch > cmaxh)
- cmaxh = ch;
- if (chh > cmaxh)
- cmaxh = chh;
-
- // calculate the bigger of text/callout
- int h = 0;
- if (cmaxh > h)
- h = cmaxh;
- if (max.cy > h)
- h = max.cy;
-
- // calculate vertical offsets of text/callout within max spacing
- int to = (h - max.cy) / 2,
- co = (h - cmaxh) / 2;
-
- // max width for text is half of the view window
- if (max.cx > ((g_sizeImage.cx - DEFAULTVIEWSBWIDTH) >> 1))
- max.cx = ((g_sizeImage.cx - DEFAULTVIEWSBWIDTH) >> 1);
-
- // go back through all the controls and place the text while
- // creating the corresponding callouts
- HDC hDC = CreateCompatibleDC(NULL);
- CPaintHelper ph(ui.m_uig, hDC);
- ph.SetElement(UIE_DEVOBJ);
- int at = 0; // Start at second row since first row is used for header. Also half row spacing
- for (i = 0; i < n; i++)
- {
- // reposition the text
- CDeviceViewText *pText = pView->GetText(i);
- if (!pText)
- {
- DeleteDC(hDC);
- return E_FAIL;
- }
-
- SIZE s = GetRectSize(pText->GetRect());
- if (bUseTwoColumns)
- {
- int iXOffset = i & 1 ? ((g_sizeImage.cx - DEFAULTVIEWSBWIDTH) >> 1) : 0;
-
- RECT rect = {iXOffset,
- at + to,
- max.cx + iXOffset,
- at + to + s.cy};
- // Get the rectangle that is actually used.
- RECT adjrect = rect;
- if (hDC)
- {
- DrawText(hDC, pText->GetText(), -1, &adjrect, DT_NOPREFIX|DT_CALCRECT);
- // If the rect actually used is smaller than the space available, use the smaller rect and align to right.
- if (adjrect.right < rect.right)
- rect.left += rect.right - adjrect.right;
- }
- pText->SetRect(rect);
- }
- else
- {
- RECT rect = {0, at + to, max.cx /*> ((g_sizeImage.cx - DEFAULTVIEWSBWIDTH) >> 1) ?
- ((g_sizeImage.cx - DEFAULTVIEWSBWIDTH) >> 1) : max.cx*/, at + to + s.cy};
- pText->SetRect(rect);
- }
-
- // create the control
- CDeviceControl *pControl = pView->NewControl();
- if (!pControl)
- {
- DeleteDC(hDC);
- return E_FAIL;
- }
-
- // position it
- RECT rect = {max.cx + 10, at, (g_sizeImage.cx - DEFAULTVIEWSBWIDTH) >> 1, at + h};
- // If single column, extend callout all the way to right end of view window
- if (!bUseTwoColumns)
- rect.right = g_sizeImage.cx - DEFAULTVIEWSBWIDTH;
- // If this is a keyboard, move to right column on odd numbered controls.
- if (bUseTwoColumns && (i & 1))
- {
- rect.left += (g_sizeImage.cx - DEFAULTVIEWSBWIDTH) >> 1;
- rect.right = g_sizeImage.cx - DEFAULTVIEWSBWIDTH;
- }
- pControl->SetCalloutMaxRect(rect);
-
- // align it
- pControl->SetAlignment(CAF_LEFT);
-
- // set approp offset
- pControl->SetObjID(os.pdoi[i].dwType);
-
- // init it
- pControl->Init();
-
- // go to next y coord
- // If this is a keyboard, then only increase y when we are moving to even numbered controls.
- if (!bUseTwoColumns || (i & 1))
- at += h;
- }
- DeleteDC(hDC);
-
- // make selection/thumb images (just for kicks)
- pView->MakeMissingImages();
-
- // calculate view dimensions (for scrolling)
- pView->CalcDimensions();
-
- return S_OK;
- }
-
- // Creates a single view with an error message. Should not fail.
- HRESULT PopulateErrorView(CDeviceUI &ui)
- {
- // create the new view
- CDeviceView *pView = ui.NewView();
- if (!pView)
- return E_FAIL;
-
- // add text objects containing error message
- pView->AddWrappedLineOfText(
- (HFONT)ui.m_uig.GetFont(UIE_ERRORHEADER),
- ui.m_uig.GetTextColor(UIE_ERRORHEADER),
- ui.m_uig.GetBkColor(UIE_ERRORHEADER),
- _T("Error!"));
- pView->AddWrappedLineOfText(
- (HFONT)ui.m_uig.GetFont(UIE_ERRORMESSAGE),
- ui.m_uig.GetTextColor(UIE_ERRORMESSAGE),
- ui.m_uig.GetBkColor(UIE_ERRORMESSAGE),
- _T("Could not create views for device."));
-
- pView->MakeMissingImages();
-
- return S_OK;
- }
-